﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace Tzync
{
    /***************************************************************************************************/
    /* This Class acts as an interface between the metadata files and the Tree of Nodes in the program */
    /***************************************************************************************************/

    public class MetaData
    {
        //Variables of logFile Class
        bool secondTime = false;
        int logFileCreateCounter, nodeIndex, flag;
        private String rootFolder;
        private String cpuID;
        private String logFilePath = Directory.GetCurrentDirectory();
        private List<TreeNode> arrNodes = new List<TreeNode>();
        private String cpuIdA, cpuIdB;      
        private List<long> DirectorySize = new List<long>();

        //Constructor loads the address of the folder selected

        public MetaData(String address, String cpuID)
        {
            flag = 0;
            rootFolder = address;
            this.cpuID = cpuID;
            logFileCreateCounter = 0;
            secondTime = false;
        }

        //Function to read from the logFile (if it exists) or create one and Create Tree of TreeNodes.

        public SystemType readFromFile(ref bool st, ref bool firstTime)
        {
            //load from file. create a Node
            int counter = 0;
            TextReader tr;
            StreamWriter SW;
            String input = "", temp = cpuID, cpuIDFromFile, fileName;
            TreeNode n;                                   
            FileStream fs, fs1;
            DirectoryInfo D;
            logFilePath = Path.Combine(logFilePath, @"Tzync\MetaData");            

            if (File.Exists(logFilePath))
            {
                // open file
                tr = new StreamReader(logFilePath);
                while ((input = tr.ReadLine()) != null)
                {
                    if (input.Trim().Length != 0)
                    {
                        n = new TreeNode(input);
                        arrNodes.Add(n);
                    }
                }
                // close the stream
                tr.Close();

                cpuIDFromFile = Directory.GetCurrentDirectory();
                cpuIDFromFile = Path.Combine(cpuIDFromFile, @"Tzync\SystemData");

                //MacFile not found exception handled
                try
                {
                    if (!File.Exists(cpuIDFromFile))
                        throw new FileNotFoundException("Exception");
                }
                catch (Exception e)
                {
                    MessageBox.Show("Exception caught: " + e.ToString());
                }

                if (File.Exists(cpuIDFromFile))
                {
                    //Open file
                    tr = new StreamReader(cpuIDFromFile);
                    while ((input = tr.ReadLine()) != null)
                    {
                        if (input.Trim().Length != 0)
                        {
                            if (counter == 0) cpuIdA = input;
                            if (counter == 1) cpuIdB = input;
                            counter++;
                        }
                    }
                    tr.Close();
                    //Stream Closed

                    if (counter == 1 && cpuIdA.CompareTo(temp) != 0)
                    {
                        secondTime = true;
                        SW = File.AppendText(cpuIDFromFile);
                        SW.WriteLine(temp);
                        SW.Close();
                        cpuIdB = temp;
                    }
                }

                st = secondTime; firstTime = false;
                return (temp == cpuIdA) ? SystemType.Host : SystemType.Guest;
            }

            else
            {
                logFilePath = Directory.GetCurrentDirectory();
                logFilePath = Path.Combine(logFilePath, @"Tzync");
                cpuIDFromFile = logFilePath;
                
                //Creating the path and the logFile
                Directory.CreateDirectory(logFilePath);
                fileName = "MetaData";
                logFilePath = Path.Combine(logFilePath, fileName);
                fs = File.Create(logFilePath);
                fs.Close();

                //macFile                
                cpuIDFromFile = Path.Combine(cpuIDFromFile, "SystemData");
                fs1 = File.Create(cpuIDFromFile);
                fs1.Close();

                SW = File.AppendText(cpuIDFromFile);
                SW.WriteLine(temp);
                SW.Close();
                //macFile ends

                D = new DirectoryInfo(@rootFolder);
                DFS(D, 0);
                writeToFile();

                st = secondTime; firstTime = true;
                return SystemType.Host;
            }
        }

        /*********************************************************/
        /* Accessory Functions for the data members of the class */
        /*********************************************************/

        public TreeNode getNode(int index)
        {
            if (index < arrNodes.Count)
                return arrNodes[index];
            else return null;
        }

        public void setNode(int index, TreeNode n)
        {
            if (index < arrNodes.Count)
                arrNodes[index] = n;
        }

        public void addNode(TreeNode n)
        {
            arrNodes.Add(n);
        }

        public List<TreeNode> getAllNodes()
        {
            return arrNodes;
        }

        /**************************************************************/
        /* Accessory Functions for the data members of the class end !*/
        /**************************************************************/

        //Description     : Function to Create the log File the first time.
        //Pre-Conditions  : Parent is a valid index of arrNode array, Directory D exists.
        //Post-Conditions : A Tree of TreeNode Class is created for the FIRST RUN of the software from system.       

        public int DFS(DirectoryInfo D, int parent)
        {
            int cur = logFileCreateCounter, child;
            DirectoryInfo[] subDirectories = D.GetDirectories();
            FileInfo[] subFiles = D.GetFiles();
            String DString = createEntry(D, parent, subDirectories.Count(), subFiles.Count());
            TreeNode n = new TreeNode(DString), n1;
            arrNodes.Add(n);

            for (int i = 0; i < subFiles.Count(); i++)
            {
                DString = logFileCreateCounter.ToString() + "|"; ;
                //add each File info  
                DString = DString + subFiles[i].FullName + "|" + "|" + "1,0" + "|" + subFiles[i].Length + "|" + "0,0" + "|";
                DString = DString + "0" + "|" + subFiles[i].LastWriteTime + "|" + subFiles[i].LastWriteTime + "|";
                DString = DString + cur.ToString() + "|";
                n1 = new TreeNode(DString);
                arrNodes.Add(n1);
                arrNodes[cur].addChild(logFileCreateCounter);
                logFileCreateCounter++;
            }

            for (int i = 0; i < subDirectories.Count(); i++)
            {
                child = DFS(subDirectories[i], cur);
                arrNodes[cur].addChild(child);
            }

            arrNodes[cur].addChild(-1);
            n.setChilds(n.dynamicChildList);
            return cur;
        }

        //Description     : Function to create a logFile entry for a Directory
        //Pre-Conditions  : Parent is a valid arrNode index, Directory D exists
        //Post-Conditions : A string is created to be given to TreeNode class to create a Tree node from it      

        private String createEntry(DirectoryInfo D, int parent, int f, int d)
        {
            long size = CalculateDirectorySize(D, logFileCreateCounter);
            String DString = logFileCreateCounter.ToString() + "|";
            DString = DString + D.FullName + "|" + "|" + "1,0" + "|" + size.ToString() + "|" + "0,0" + "|";
            DString = DString + "0" + "|" + D.LastWriteTime + "|" + D.LastWriteTime + "|" + parent.ToString() + "|" + "-1";
            logFileCreateCounter++;
            return DString;
        }

        //Description     : Function to calculate directory size
        //Pre-Conditions  : Directory D exists
        //Post-Conditions : Size calculated       

        long CalculateDirectorySize(DirectoryInfo directory, int nI)
        {
            if (flag != 0 && DirectorySize[nI] != -1) return DirectorySize[nI];

            int cur = nodeIndex;
            DirectorySize.Add(-1);
            nodeIndex++;
            long totalSize = 0;

            // Examine all contained files.
            FileInfo[] files = directory.GetFiles();
            foreach (FileInfo file in files)
            {
                totalSize += file.Length;
                nodeIndex++;
                DirectorySize.Add(file.Length);
            }

            DirectoryInfo[] dirs = directory.GetDirectories();
            foreach (DirectoryInfo dir in dirs)
            {
                totalSize += CalculateDirectorySize(dir, nodeIndex);
            }

            return DirectorySize[cur] = totalSize;
        }


        //Description     : Function to write to logFile
        //Pre-Conditions  : logFilePath address is correct
        //Post-Conditions : logFile is written       

        public void writeToFile()
        {
            StreamWriter SW;
            File.Delete(logFilePath);
            FileStream fs1 = File.Create(logFilePath);
            fs1.Close();

            SW = File.AppendText(logFilePath);
            foreach (TreeNode n in arrNodes)
            {
                SW.WriteLine(n.toString());
            }
            SW.Close();
        }        

    }

    /***********************/
    /* Class MetaData ends */
    /***********************/
}
